基础的游戏输入处理
在游戏开发中,处理玩家的输入是非常关键的一环。Dora SSR 引擎为我们提供了丰富的 API 来处理各种输入方式,包括触摸/点击、键盘、输入法、鼠 标和游戏控制器。本教程将带你了解如何以事件回调和每帧轮询两种方式来处理这些输入。事件回调和每帧轮询在输入处理上的主要区别在于触发机制和适用场景:
-
事件回调:是由系统在特定输入事件发生时自动触发的,响应及时,性能更高,适合处理瞬时、离散的输入事件,如点击、按键等,代码更模块化;
-
每帧轮询:需要在游戏的更新循环中主动检查输入设备的状态,适用于需要持续监控输入状态的情况,如角色移动、持续按键等,提供了更大的灵活性,但可能对性能有一定影响。综合而言,事件回调更适合即时响应的输入处理,每帧轮询则更适合需要持续检测和复杂输入逻辑的场景。
1. 触摸/点击输入
1.1 事件回调方式
Dora SSR 提供了一系列方法来监听节点的触摸/点击事件,触摸事件是指在触摸屏上的操作,点击事件是指通过鼠标设备的操作,通常这两者会有相似的处理方式。我们可以使用 onTapBegan
、onTapMoved
、onTapEnded
和 onTapped
方法来监听这些事件。需要通过创建一个场景节点对象进行调用。
- Lua
- Teal
- TypeScript
- YueScript
local Node <const> = require("Node")
local Size <const> = require("Size")
local button = Node()
button.size = Size(100, 100)
button.showDebug = true
button:onTapBegan(function(touch)
-- touch 是一个包含触摸信息的对象
-- 可以通过 touch.location 获取相对于 button 节点的触摸位置
print("点击开始于", touch.location)
end)
button:onTapMoved(function(touch)
print("点击移动到", touch.location)
end)
button:onTapEnded(function(touch)
print("点击结束于", touch.location)
end)
button:onTapped(function(touch)
print("完成一次点击于", touch.location)
end)
local Node <const> = require("Node")
local Size <const> = require("Size")
local type Touch = require("Touch")
local button = Node()
button.size = Size(100, 100)
button.showDebug = true
button:onTapBegan(function(touch: Touch.Type)
-- touch 是一个包含触摸信息的对象
-- 可以通过 touch.location 获取相对于 button 节点的触摸位置
print("点击开始于", touch.location)
end)
button:onTapMoved(function(touch: Touch.Type)
print("点击移动到", touch.location)
end)
button:onTapEnded(function(touch: Touch.Type)
print("点击结束于", touch.location)
end)
button:onTapped(function(touch: Touch.Type)
print("完成一次点击于", touch.location)
end)
import { Node, Size } from "Dora";
const button = Node();
button.size = Size(100, 100);
button.showDebug = true;
button.onTapBegan(touch => {
// touch 是一个包含触摸信息的对象
// 可以通过 touch.location 获取相对于 button 节点的触摸位置
print("点击开始于", touch.location);
});
button.onTapMoved(touch => {
print("点击移动到", touch.location);
});
button.onTapEnded(touch => {
print("点击结束于", touch.location);
});
button.onTapped(touch => {
print("完成一次点击于", touch.location);
});
_ENV = Dora
with Node!
.size = Size 100, 100
.showDebug = true
\onTapBegan (touch) ->
-- touch 是一个包含触摸信息的对象
-- 可以通过 touch.location 获取相对于 button 节点的触摸位置
print "点击开始于", touch.location
\onTapMoved (touch) ->
print "点击移动到", touch.location
\onTapEnded (touch) ->
print "点击结束于", touch.location
\onTapped (touch) ->
print "完成一次点击于", touch.location
说明:
onTapBegan
:当触摸开始时触发。onTapMoved
:当触摸在屏幕上移动时触发。onTapEnded
:当触摸结束时触发。onTapped
:当一次完整的点击(点击并抬起)完成时触发。
触摸/点击事件过滤器
我们还可以通过注册 onTapFilter
方法来设置触摸/点击事件的过滤器,只有通过过滤器的事件才会触发回调。onTapFilter
回调会在 onTapBegan
之前触发。
- Lua
- Teal
- TypeScript
- YueScript
button:onTapFilter(function(touch)
-- 如果为多点触摸的情况,只处理第一个触摸点
if not touch.first then
-- 将触摸事件的 enabled 属性设置为 false
-- 使得该触摸事件不会触发后续的 onTapBegan 等回调
touch.enabled = false
end
end)
button:onTapFilter(function(touch: Touch.Type)
-- 如果为多点触摸的情况,只处理第一个触摸点
if not touch.first then
-- 将触摸事件的 enabled 属性设置为 false
-- 使得该触摸事件不会触发后续的 onTapBegan 等回调
touch.enabled = false
end
end)
button.onTapFilter(touch => {
// 如果为多点触摸的情况,只处理第一个触摸点
if (!touch.first) {
// 将触摸事件的 enabled 属性设置为 false
// 使得该触摸事件不会触发后续的 onTapBegan 等回调
touch.enabled = false;
}
});
button\onTapFilter (touch) ->
-- 如果为多点触摸的情况,只处理第一个触摸点
unless touch.first
-- 将触摸事件的 enabled 属性设置为 false
-- 使得该触摸事件不会触发后续的 onTapBegan 等回调
touch.enabled = false
多点触摸事件
Dora SSR 还支持多点触摸事件,可以通过 onGesture
方法来监听。
- Lua
- Teal
- TypeScript
- YueScript
button:onGesture(function(center, numTouches, deltaDist, angle)
-- center: 所有触摸位置的中心
-- numTouches: 触摸点的数量
-- deltaDist: 变化的运动比例(相对于屏幕尺寸)
-- angle: 沿着触摸中心旋转的角度,单位为弧度
print("center:", center, "numTouches:", numTouches, "deltaDist:", delta, "angle:", angle)
end)
button:onGesture(function(center: Vec2.Type, numTouches: integer, deltaDist: number, angle: number)
-- center: 所有触摸位置的中心
-- numTouches: 触摸点的数量
-- deltaDist: 变化的运动比例(相对于屏幕尺寸)
-- angle: 沿着触摸中心旋转的角度,单位为弧度
print("center:", center, "numTouches:", numTouches, "deltaDist:", delta, "angle:", angle)
end)
button.onGesture((center, numTouches, deltaDist, angle) => {
// center: 所有触摸位置的中心
// numTouches: 触摸点的数量
// deltaDist: 变化的运动比例(相对于屏幕尺寸)
// angle: 沿着触摸中心旋转的角度,单位为弧度
print("center:", center, "numTouches:", numTouches, "deltaDist:", delta, "angle:", angle);
});
button\onGesture (center, numTouches, deltaDist, angle) ->
-- center: 所有触摸位置的中心
-- numTouches: 触摸点的数量
-- deltaDist: 变化的运动比例(相对于屏幕尺寸)
-- angle: 沿着触摸中心旋转的角度,单位为弧度
print "center:", center, "numTouches:", numTouches, "deltaDist:", delta, "angle:", angle
swallowTouches
属性
通常触摸/点击事件会沿着场景节点树从根节点向下传递,并被每一个相关的节点处理。如果我们希望在某个节点上处理完触摸/点击事件后,不再继续往下传递给其子节点,可以设置 swallowTouches
属性为 true
。加上了 swallowTouches
属性的节点通常会被用作拦截触摸事件的遮罩层。
- Lua
- Teal
- TypeScript
- YueScript
button.swallowTouches = true
button.swallowTouches = true
button.swallowTouches = true;
button.swallowTouches = true
触摸事件的开关
如果需要在某个时刻暂停或恢复监听事件,如实现按钮按下后禁用点击事件,可以使用 node.touchEnabled
属性。
- Lua
- Teal
- TypeScript
- YueScript
button.touchEnabled = false
button.touchEnabled = false
button.touchEnabled = false;
button.touchEnabled = false
1.2 每帧轮询方式
由于触摸事件是即时的,不适合用每帧轮询的方式处理。然而,我们可以通过在上一级变量域范围内记录触摸状态来模拟这种方式。
- Lua
- Teal
- TypeScript
- YueScript
local Node <const> = require("Node")
local button = Node()
local isTouching = false
button:onTapBegan(function(touch)
isTouching = true
end)
button:onTapEnded(function(touch)
isTouching = false
end)
-- 在游戏的更新函数中
button:onUpdate(function()
if isTouching then
print("正在触摸")
end
end)
local Node <const> = require("Node")
local type Touch = require("Touch")
local button = Node()
local isTouching = false
button:onTapBegan(function(touch: Touch.Type)
isTouching = true
end)
button:onTapEnded(function(touch: Touch.Type)
isTouching = false
end)
-- 在游戏的更新函数中
button:onUpdate(function(): boolean
if isTouching then
print("正在触摸")
end
return false
end)
import { Node } from "Dora";
const button = Node();
let isTouching = false;
button.onTapBegan(() => {
isTouching = true;
});
button.onTapEnded(() => {
isTouching = false;
});
// 在游戏的更新函数中
button.onUpdate(() => {
if (isTouching) {
print("正在触摸");
}
return false;
});
_ENV = Dora
with Node!
isTouching = false
\onTapBegan (touch) ->
isTouching = true
\onTapEnded (touch) ->
isTouching = false
-- 在游戏的更新函数中
\onUpdate ->
if isTouching
print "正在触摸"
说明:
- 我们使用一个布尔变量
isTouching
来记录当前是否有触摸。 - 在
update
函数中,每帧检查isTouching
的状态。
2. 键盘输入
2.1 事件回调方式
可以使用 onKeyDown
、onKeyUp
和 onKeyPressed
方法来监听键盘事件。
- Lua
- Teal
- TypeScript
- YueScript
local Node <const> = require("Node")
local node = Node()
node:onKeyDown(function(keyName)
print("按下键:", keyName)
end)
node:onKeyUp(function(keyName)
print("释放键:", keyName)
end)
node:onKeyPressed(function(keyName)
print("持续按键:", keyName)
end)
local Node <const> = require("Node")
local type Keyboard = require("Keyboard")
local node = Node()
node:onKeyDown(function(keyName: Keyboard.KeyName)
print("按下键:", keyName)
end)
node:onKeyUp(function(keyName: Keyboard.KeyName)
print("释放键:", keyName)
end)
node:onKeyPressed(function(keyName: Keyboard.KeyName)
print("持续按键:", keyName)
end)
import { Node } from "Dora";
const node = Node();
node.onKeyDown(keyName => {
print("按下键:", keyName);
});
node.onKeyUp(keyName => {
print("释放键:", keyName);
});
node.onKeyPressed(keyName => {
print("持续按键:", keyName);
});
_ENV = Dora
with Node!
\onKeyDown (keyName) ->
print "按下键:", keyName
\onKeyUp (keyName) ->
print "释放键:", keyName
\onKeyPressed (keyName) ->
print "持续按键:", keyName
说明:
onKeyDown
:当按键被按下时触发。onKeyUp
:当按键被释放时触发。onKeyPressed
:当按键处于按下状态时每帧触发。